1   /*
2    * Copyright (C) 2009 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.truth.Truth.assertThat;
20  
21  import com.google.common.annotations.GwtCompatible;
22  
23  /**
24   * Tests common methods in {@link ImmutableTable}
25   *
26   * @author Gregory Kick
27   */
28  @GwtCompatible(emulated = true)
29  public class ImmutableTableTest extends AbstractTableReadTest {
30    @Override protected Table<String, Integer, Character> create(Object... data) {
31      ImmutableTable.Builder<String, Integer, Character> builder =
32          ImmutableTable.builder();
33      for (int i = 0; i < data.length; i = i + 3) {
34        builder.put((String) data[i], (Integer) data[i + 1],
35            (Character) data[i + 2]);
36      }
37      return builder.build();
38    }
39  
40    public void testBuilder() {
41      ImmutableTable.Builder<Character, Integer, String> builder =
42          new ImmutableTable.Builder<Character, Integer, String>();
43      assertEquals(ImmutableTable.of(), builder.build());
44      assertEquals(ImmutableTable.of('a', 1, "foo"), builder
45          .put('a', 1, "foo")
46          .build());
47      Table<Character, Integer, String> expectedTable = HashBasedTable.create();
48      expectedTable.put('a', 1, "foo");
49      expectedTable.put('b', 1, "bar");
50      expectedTable.put('a', 2, "baz");
51      Table<Character, Integer, String> otherTable = HashBasedTable.create();
52      otherTable.put('b', 1, "bar");
53      otherTable.put('a', 2, "baz");
54      assertEquals(expectedTable, builder
55          .putAll(otherTable)
56          .build());
57    }
58  
59    public void testBuilder_withImmutableCell() {
60      ImmutableTable.Builder<Character, Integer, String> builder =
61          new ImmutableTable.Builder<Character, Integer, String>();
62      assertEquals(ImmutableTable.of('a', 1, "foo"), builder
63          .put(Tables.immutableCell('a', 1, "foo"))
64          .build());
65    }
66  
67    public void testBuilder_withImmutableCellAndNullContents() {
68      ImmutableTable.Builder<Character, Integer, String> builder =
69          new ImmutableTable.Builder<Character, Integer, String>();
70      try {
71        builder.put(Tables.immutableCell((Character) null, 1, "foo"));
72        fail();
73      } catch (NullPointerException e) {
74        // success
75      }
76      try {
77        builder.put(Tables.immutableCell('a', (Integer) null, "foo"));
78        fail();
79      } catch (NullPointerException e) {
80        // success
81      }
82      try {
83        builder.put(Tables.immutableCell('a', 1, (String) null));
84        fail();
85      } catch (NullPointerException e) {
86        // success
87      }
88    }
89  
90    private static class StringHolder {
91      String string;
92    }
93  
94    public void testBuilder_withMutableCell() {
95      ImmutableTable.Builder<Character, Integer, String> builder =
96          new ImmutableTable.Builder<Character, Integer, String>();
97  
98      final StringHolder holder = new StringHolder();
99      holder.string = "foo";
100     Table.Cell<Character, Integer, String> mutableCell =
101         new Tables.AbstractCell<Character, Integer, String>() {
102           @Override public Character getRowKey() {
103             return 'K';
104           }
105           @Override public Integer getColumnKey() {
106             return 42;
107           }
108           @Override public String getValue() {
109             return holder.string;
110           }
111         };
112 
113     // Add the mutable cell to the builder
114     builder.put(mutableCell);
115 
116     // Mutate the value
117     holder.string = "bar";
118 
119     // Make sure it uses the original value.
120     assertEquals(ImmutableTable.of('K', 42, "foo"), builder.build());
121   }
122 
123   public void testBuilder_noDuplicates() {
124     ImmutableTable.Builder<Character, Integer, String> builder =
125         new ImmutableTable.Builder<Character, Integer, String>()
126             .put('a', 1, "foo")
127             .put('a', 1, "bar");
128     try {
129       builder.build();
130       fail();
131     } catch (IllegalArgumentException e) {
132       // success
133     }
134   }
135 
136   public void testBuilder_noNulls() {
137     ImmutableTable.Builder<Character, Integer, String> builder =
138         new ImmutableTable.Builder<Character, Integer, String>();
139     try {
140       builder.put(null, 1, "foo");
141       fail();
142     } catch (NullPointerException e) {
143       // success
144     }
145     try {
146       builder.put('a', null, "foo");
147       fail();
148     } catch (NullPointerException e) {
149       // success
150     }
151     try {
152       builder.put('a', 1, null);
153       fail();
154     } catch (NullPointerException e) {
155       // success
156     }
157   }
158 
159   private static <R, C, V> void validateTableCopies(Table<R, C, V> original) {
160     Table<R, C, V> copy = ImmutableTable.copyOf(original);
161     assertEquals(original, copy);
162     validateViewOrdering(original, copy);
163 
164     Table<R, C, V> built
165         = ImmutableTable.<R, C, V>builder().putAll(original).build();
166     assertEquals(original, built);
167     validateViewOrdering(original, built);
168   }
169 
170   private static <R, C, V> void validateViewOrdering(
171       Table<R, C, V> original, Table<R, C, V> copy) {
172     assertTrue(Iterables.elementsEqual(original.cellSet(), copy.cellSet()));
173     assertTrue(Iterables.elementsEqual(original.rowKeySet(), copy.rowKeySet()));
174     assertTrue(Iterables.elementsEqual(original.values(), copy.values()));
175   }
176 
177   public void testCopyOf() {
178     Table<Character, Integer, String> table = TreeBasedTable.create();
179     validateTableCopies(table);
180     table.put('b', 2, "foo");
181     validateTableCopies(table);
182     table.put('b', 1, "bar");
183     table.put('a', 2, "baz");
184     validateTableCopies(table);
185     // Even though rowKeySet, columnKeySet, and cellSet have the same
186     // iteration ordering, row has an inconsistent ordering.
187     assertThat(table.row('b').keySet()).has().exactly(1, 2).inOrder();
188     assertThat(ImmutableTable.copyOf(table).row('b').keySet())
189         .has().exactly(2, 1).inOrder();
190   }
191 
192   public void testCopyOfSparse() {
193     Table<Character, Integer, String> table = TreeBasedTable.create();
194     table.put('x', 2, "foo");
195     table.put('r', 1, "bar");
196     table.put('c', 3, "baz");
197     table.put('b', 7, "cat");
198     table.put('e', 5, "dog");
199     table.put('c', 0, "axe");
200     table.put('e', 3, "tub");
201     table.put('r', 4, "foo");
202     table.put('x', 5, "bar");
203     validateTableCopies(table);
204   }
205 
206   public void testCopyOfDense() {
207     Table<Character, Integer, String> table = TreeBasedTable.create();
208     table.put('c', 3, "foo");
209     table.put('c', 2, "bar");
210     table.put('c', 1, "baz");
211     table.put('b', 3, "cat");
212     table.put('b', 1, "dog");
213     table.put('a', 3, "foo");
214     table.put('a', 2, "bar");
215     table.put('a', 1, "baz");
216     validateTableCopies(table);
217   }
218 
219   public void testBuilder_orderRowsAndColumnsBy_putAll() {
220     Table<Character, Integer, String> table = HashBasedTable.create();
221     table.put('b', 2, "foo");
222     table.put('b', 1, "bar");
223     table.put('a', 2, "baz");
224     ImmutableTable.Builder<Character, Integer, String> builder
225         = ImmutableTable.builder();
226     Table<Character, Integer, String> copy
227         = builder.orderRowsBy(Ordering.natural())
228             .orderColumnsBy(Ordering.natural())
229             .putAll(table).build();
230     assertThat(copy.rowKeySet()).has().exactly('a', 'b').inOrder();
231     assertThat(copy.columnKeySet()).has().exactly(1, 2).inOrder();
232     assertThat(copy.values()).has().exactly("baz", "bar", "foo").inOrder();
233     assertThat(copy.row('b').keySet()).has().exactly(1, 2).inOrder();
234   }
235 
236   public void testBuilder_orderRowsAndColumnsBy_sparse() {
237     ImmutableTable.Builder<Character, Integer, String> builder
238         = ImmutableTable.builder();
239     builder.orderRowsBy(Ordering.natural());
240     builder.orderColumnsBy(Ordering.natural());
241     builder.put('x', 2, "foo");
242     builder.put('r', 1, "bar");
243     builder.put('c', 3, "baz");
244     builder.put('b', 7, "cat");
245     builder.put('e', 5, "dog");
246     builder.put('c', 0, "axe");
247     builder.put('e', 3, "tub");
248     builder.put('r', 4, "foo");
249     builder.put('x', 5, "bar");
250     Table<Character, Integer, String> table = builder.build();
251     assertThat(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
252     assertThat(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
253     assertThat(table.values()).has().exactly("cat", "axe", "baz", "tub",
254         "dog", "bar", "foo", "foo", "bar").inOrder();
255     assertThat(table.row('c').keySet()).has().exactly(0, 3).inOrder();
256     assertThat(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
257   }
258 
259   public void testBuilder_orderRowsAndColumnsBy_dense() {
260     ImmutableTable.Builder<Character, Integer, String> builder
261         = ImmutableTable.builder();
262     builder.orderRowsBy(Ordering.natural());
263     builder.orderColumnsBy(Ordering.natural());
264     builder.put('c', 3, "foo");
265     builder.put('c', 2, "bar");
266     builder.put('c', 1, "baz");
267     builder.put('b', 3, "cat");
268     builder.put('b', 1, "dog");
269     builder.put('a', 3, "foo");
270     builder.put('a', 2, "bar");
271     builder.put('a', 1, "baz");
272     Table<Character, Integer, String> table = builder.build();
273     assertThat(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
274     assertThat(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
275     assertThat(table.values()).has().exactly("baz", "bar", "foo", "dog",
276         "cat", "baz", "bar", "foo").inOrder();
277     assertThat(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
278     assertThat(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
279   }
280 
281   public void testBuilder_orderRowsBy_sparse() {
282     ImmutableTable.Builder<Character, Integer, String> builder
283         = ImmutableTable.builder();
284     builder.orderRowsBy(Ordering.natural());
285     builder.put('x', 2, "foo");
286     builder.put('r', 1, "bar");
287     builder.put('c', 3, "baz");
288     builder.put('b', 7, "cat");
289     builder.put('e', 5, "dog");
290     builder.put('c', 0, "axe");
291     builder.put('e', 3, "tub");
292     builder.put('r', 4, "foo");
293     builder.put('x', 5, "bar");
294     Table<Character, Integer, String> table = builder.build();
295     assertThat(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
296     assertThat(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
297   }
298 
299   public void testBuilder_orderRowsBy_dense() {
300     ImmutableTable.Builder<Character, Integer, String> builder
301         = ImmutableTable.builder();
302     builder.orderRowsBy(Ordering.natural());
303     builder.put('c', 3, "foo");
304     builder.put('c', 2, "bar");
305     builder.put('c', 1, "baz");
306     builder.put('b', 3, "cat");
307     builder.put('b', 1, "dog");
308     builder.put('a', 3, "foo");
309     builder.put('a', 2, "bar");
310     builder.put('a', 1, "baz");
311     Table<Character, Integer, String> table = builder.build();
312     assertThat(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
313     assertThat(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
314   }
315 
316   public void testBuilder_orderColumnsBy_sparse() {
317     ImmutableTable.Builder<Character, Integer, String> builder
318         = ImmutableTable.builder();
319     builder.orderColumnsBy(Ordering.natural());
320     builder.put('x', 2, "foo");
321     builder.put('r', 1, "bar");
322     builder.put('c', 3, "baz");
323     builder.put('b', 7, "cat");
324     builder.put('e', 5, "dog");
325     builder.put('c', 0, "axe");
326     builder.put('e', 3, "tub");
327     builder.put('r', 4, "foo");
328     builder.put('x', 5, "bar");
329     Table<Character, Integer, String> table = builder.build();
330     assertThat(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
331     assertThat(table.row('c').keySet()).has().exactly(0, 3).inOrder();
332   }
333 
334   public void testBuilder_orderColumnsBy_dense() {
335     ImmutableTable.Builder<Character, Integer, String> builder
336         = ImmutableTable.builder();
337     builder.orderColumnsBy(Ordering.natural());
338     builder.put('c', 3, "foo");
339     builder.put('c', 2, "bar");
340     builder.put('c', 1, "baz");
341     builder.put('b', 3, "cat");
342     builder.put('b', 1, "dog");
343     builder.put('a', 3, "foo");
344     builder.put('a', 2, "bar");
345     builder.put('a', 1, "baz");
346     Table<Character, Integer, String> table = builder.build();
347     assertThat(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
348     assertThat(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
349   }
350 }
351